import { Component, OnInit, ViewChild, ChangeDetectionStrategy, ChangeDetectorRef, SimpleChanges, ElementRef, NgZone } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, FormArray } from '@angular/forms';
import { Router, ActivatedRoute } from "@angular/router";
import { NzMessageService } from "ng-zorro-antd";
import { FcsService } from "../../../service/fcs.service";
import { UploadParam, Region, EnvVariable } from "../../../shared-component/class/instance";
import { CodeService } from "../../../service/code.service";
import { CommonService } from "../../../service/common.service";
import { debounceTime, distinctUntilChanged, first, map, switchMap } from 'rxjs/operators';
import { Observable, Subscriber } from 'rxjs';
import { Environment } from 'environments/environment';
import { FcsCreateTriggerComponent } from '../../../shared-component/fcs-create-trigger/fcs-create-trigger.component';
import { DomSanitizer } from '@angular/platform-browser';


@Component({
	selector: 'app-function-create',
	templateUrl: './function-create.component.html',
	styleUrls: ['./function-create.component.less']
})
export class FunctionCreateComponent implements OnInit {
	@ViewChild('functionFormComponent', { static: false }) functionFormComponent;
	@ViewChild('triggerCreate', { static: false }) triggerCreate: FcsCreateTriggerComponent;
	functionForm: FormGroup;
	originApplicationList;
	applicationList;
	applicationId: string; // 从应用列表表格中 创建函数 传递过来的 应用id，创建函数成功后，要跳转到函数详情页面
	selectApplicationId: string; // 应用下拉选择框选中的应用id
	groupId: string; // 从函数列表传递过来的应用id
	groupDisplayName: string;
	regionList = [];
	currentRegion: Region = {
		regionCode: '',
		regionName: ''
	};
	runtimeList = [
		{ key: 'python2.7', value: 'Python 2.7', code: false, icon: "#icon-runtimepython" },
		{ key: 'python3.6', value: 'Python 3.6', code: false, icon: "#icon-runtimepython" },
		{ key: 'nodejs10.22', value: 'Nodejs 10.22', code: false, icon: "#icon-runtimeNodejs" },
		{ key: 'nodejs12.18', value: 'Nodejs 12.18', code: false, icon: "#icon-runtimeNodejs" },
		{ key: 'golang1', value: 'Golang 1', code: false, icon: "#icon-runtimego" },
		{ key: 'java8', value: 'Java 8', code: false, icon: "#icon-runtimejava" },
		{ key: 'custom-container', value: '自定义镜像', code: false, icon: "#icon-runtimeDocker" },
	]; // code为是否获取到了code
	RuntimeCustomContainer = "custom-container"
	runtimeClassifyList = [];
	runtimeClassfy: string = '';
	sceneClassfy: string = '';
	sceneClassifyList = [];
	uploadType = 'online'; //upload
	isCodeLoading: boolean = false; //是否在加载在线代码
	code = null;
	localCode = null;
	fileMaxSize = 50;
	uploadFiles = []; //上传的文件
	isZipFile: boolean = true;
	exceedFileMaxSize: boolean = false;
	focusFileInput: boolean = false;
	isLoadingApplication = true;
	errorMsg = '';
	versionName = 'LATEST';
	downLink = '';
	uploadParam: UploadParam;
	regionName: string;
	runtime: string = "python3.6"; //运行环境
	functionId: string; //创建函数成功后，从返回值中获取的新创建的函数的functionId
	notFind: boolean = false; //没有查找到对应的应用
	searchApplicationValue: string = '';
	ossBucket: string;
	ossFile: string;
	isReadonly: boolean = false;
	uploadTypeList = [
		{ label: '在线编辑', value: 'online' },
		{ label: '本地上传', value: 'upload' },
		{ label: '从 OSS 上传', value: 'oss' }
	];
	ossBucketList = [];
	isLoadingBucket: boolean = false;
	isShowSingle: boolean = true;
	isInternetAccess: boolean = false; //是否开启公网访问权限
	isVirtualAccess: boolean = false; //是否开启公有网络
	isLoadingVPC: boolean = false; //是否正在加载VPC
	isBindingLayers: boolean = false; //是否开启层配置
	layerList = [] // 层列表
	layerVersionList = [] // 层版本列表
	vpcId: string;
	vpcList = []; // vpc集合
	subnetId: string;
	subnetList = [];
	tabs2 = [];
	disableSubmit: boolean = false;
	handlerPlaceHolder = 'index.handler';
	createFunctionMsgId;
	vpcError: boolean = false;
	subnetError: boolean = false;
	regionCode: string = ''; //当前选中的region
	notChange: boolean = false;
	envVariablesData: EnvVariable[] = [];
	envVariables: EnvVariable[] = [];
	envValid: boolean = true;
	needValid: boolean = false; //初始化环境变量的时候，是否需要校验；如果是确定后，环境变量没有校验通过，又传递过去，则校验；反正不校验
	createTypeList = [
		{ createTypeCode: 'function', createTypeName: '新建空白函数' },
		{ createTypeCode: 'template', createTypeName: '通过模板创建' },
	];
	createType: string = 'function';
	isTemplateList: boolean = false;
	isTemplateDetail: boolean = false;
	templateList;
	createFunction;
	tplPageNo: number = 1;
	tplPageSize: number = 12;
	searchTplValue: string = '';
	tplTotal: number = 30;
	checkedTplId: string;
	checkedTplName: string;
	checkedTpl;
	theTplDetail;
	isLoadingTemplates: boolean = false;
	LATESTobj;
	triggerData = []; // 如果是使用模板创建函数，有需要创建的触发器，则将需要创建的触发器配置返回在 triggerData中
	isFinishCreatingTriggers: boolean = true;
	createFunctionId: string;
	triggerMsgId;
	zipPlace: string = '选择上传文件，格式为 zip';
	jarPlace: string = '选择上传文件，格式为 zip / jar';
	filePlaceholder: string = this.zipPlace;
	isJarFile: boolean = true;
	cirImageList = [];
	isInitialize = false;

	// 在线编辑器 iframe 对象
	@ViewChild('codeEditor', { static: false }) codeEditor: ElementRef;
	// vscode ide iframe url
	ideUrl = null;

	pageNo = 1; // 层列表分页
	pageSize = 1000;
	layerId = ''; // 层列表所选层id
	layerMax = false; // 层最多创建数开关
	layerVersionIds = []; // 选择层的版本id
	layerLength = 0; // 返回层的条数
	layerVersionSelected = [] //已选的版本

	constructor(
		private router: Router,
		private activatedRoute: ActivatedRoute,
		private fb: FormBuilder,
		private fcsService: FcsService,
		private codeService: CodeService,
		private msgService: NzMessageService,
		private commonService: CommonService,
		private sanitizer: DomSanitizer,
		private zone: NgZone
	) {
		this.ideUrl = this.sanitizer.bypassSecurityTrustResourceUrl("/ifcs/editor/index.html");
		this.functionForm = this.fb.group({
			functionName: ['', [Validators.required, this.nameValidator()], [this.nameDuplicateValidator()]],
			groupId: ['', [Validators.required]],
			regionCode: ['', [Validators.required]],
			description: ['', [Validators.maxLength(500), this.descriptionValid]],
			runtime: ['python3.6', [Validators.required]],
			handler: ['index.handler', [Validators.required]],
			memorySize: [128, [Validators.required]],
			timeout: [10, [Validators.required]],
			concurrency: [1, [Validators.required]],
			reserveNumber: [0, [Validators.required]],
			upload: [this.uploadType],
			fileName: ['', [Validators.required, this.fileNameValidator]],
			ossBucket: ['', [Validators.required]],
			ossFile: ['', [Validators.required, this.ossFileValidator]],
			internetAccess: [false, [Validators.required]],
			virtualAccess: [false, [Validators.required]],
			bindingLayers: [false],
			vpc: [undefined, [Validators.required]],
			subnet: [undefined, [Validators.required]],
			createType: ['function', [Validators.required]],

			containerImage: [null, [this.containerValidator]],
			containerCommand: ["", [this.commandValidator]],
			containerArgs: ["", [this.commandValidator]],
			containerPort: ["8080", [Validators.pattern("[0-9]*"),
			Validators.pattern("^((?!^(8012|8013|8022|9090|9091|9092)$).)*$"),
			Validators.min(1), Validators.max(65535)]],

			isInitialize: [false],
			initializeHandler: ["", [this.initValidator]],
			initializeTimeout: [3, [this.initValidator]],
		});
	}

	// 获取表单的formArray
	get layersList(): FormArray {
		return this.functionForm.get('layersList') as FormArray;
	}


	ngOnChanges(simpleChanges: SimpleChanges) {
		if (simpleChanges.templateList && simpleChanges.templateList.currentValue != simpleChanges.templateList.previousValue) {
			this.zone.run(() => { });
		}
	}

	ngOnInit() {
		this.applicationId = this.activatedRoute.snapshot.queryParams['applicationId'];
		this.groupId = this.activatedRoute.snapshot.queryParams['groupId'];
		this.getRegion();
		this.getApplicationList();
		this.getVPCList();
		this.runtimeList.forEach(item => this.runtimeClassifyList.push(item));
		this.runtimeClassifyList.unshift({ key: '', value: '全部', code: false });
		this.getTemplateScenesConditions();
		this.getCirTagList(); // 获取容器镜像服务的项目列表
		this.getLayersList(); // 获取层列表
	}

	// 添加一行时，需要为对应的formArray添加一个formGroup
	addField(name) {
		let formControl = this.layersList.controls;
		let layerIdSelected = [];
		if (formControl.length >= 5 || formControl.length === this.layerLength) { // 最多添加5个
			this.layerMax = true;
			return false;
		} else {
			this.layerMax = false;
		}

		for (let m = 0; m < formControl.length; m++) {
			let formGroup = formControl[m] as FormGroup;
			layerIdSelected.push(formGroup.get('layer').value);
			this.layerVersionSelected.push(formGroup.get('layerVersion').value);
		}
		// 过滤已选的层版本的层列表
		this.layerList.map(v=>{
            if(v.versions.length === 1){
				if(layerIdSelected.includes(v.layerId) ){
					this.layerList = this.layerList.filter(i => !(layerIdSelected.includes(i.layerId)))
				}
			} else {
				if(layerIdSelected.includes(v.layerId) && v.versions.length === formControl.length){
					this.layerList = this.layerList.filter(i => !(layerIdSelected.includes(i.layerId)))
				}
			}

		})



		if (this.functionFormComponent.validControl(name)) {
			this.layersList.push(this.createAddrItem('layersList'));
			this.layerVersionList = []
		}
	}

	// 删除一行
	removeField(i: number, type): void {
		this.layersList.removeAt(i);
		this.layerMax = false;
	}


	// 创建一个表单的formGroup
	private createAddrItem(type): FormGroup {
		return this.fb.group({
			layer: [null, [Validators.required]],
			layerVersion: [null, [Validators.required]]
		});
	}

	containerValidator(control: FormControl): any {
		if (!control.parent || control.parent.get("runtime").value != "custom-container") {
			return null
		}
		if (!control.value) {
			return {
				valid: false
			}
		}
		return null;
	}
	commandValidator(control: FormControl): any {
		if (!control.value) {
			return null
		}
		try {
			let data = JSON.parse(control.value)
			if (!(data instanceof Array)) {
				return {
					valid: false,
				}
			}
		} catch (error) {
			return {
				valid: false,
			}
		}
		return null;
	}
	initValidator(control: FormControl): any {
		if (!control.parent
			|| control.parent.get("runtime").value == "custom-container"
			|| control.parent.get("isInitialize").value == false) {
			return null
		}
		if (!control.value) {
			return {
				valid: false
			}
		}
		return null;
	}

	createTypeChange(event) {
		if (event && event === 'template') {
			if (!this.checkedTplId) {
				this.isTemplateList = true;
				this.getTemplateList();
			}
		} else {
			this.isTemplateList = false;
		}
	}

	runtimeClassfyChange(event) {
		this.getTemplateList();
	}

	sceneClassfyChange(event) {
		this.getTemplateList();
	}

	refreshTemplateList() {
		// this.tplPageNo = 1;
		// this.searchTplValue = "";
		// this.sceneClassfy = "";
		// this.runtimeClassfy = "";
		this.getTemplateList();
	}
	/**
	*  获取层列表
	* @memberof FunctionCreateComponent
	*/
	getLayersList() {
		this.fcsService.getLayerByRuntime(this.runtime).subscribe(res => {
			this.layerList = res || [];
			this.layerLength = this.layerList.length;
			this.layerId = this.layerList[0].layerId
		})
	}
	changeLayer(val,i) {
		if (val) {
			this.layersList.controls[i].get('layerVersion').setValue(null)
			this.layerId = val;
			this.layerVersionList = this.layerList.filter(v => v.layerId === val)[0].versions.filter(i=>!(this.layerVersionSelected.includes(i.versionId))); // 去除已选层的 和 版本
		}
		else {
			this.layerVersionList = []
		}
	}

	getTemplateList() {
		this.isLoadingTemplates = true;
		this.fcsService.getTemplateData(this.tplPageNo, this.tplPageSize, this.searchTplValue, this.sceneClassfy, this.runtimeClassfy).subscribe(res => {
			this.isLoadingTemplates = false;
			this.templateList = res['data'] || [];
			for (let item of this.templateList) {
				if (item.id === this.checkedTplId) {
					item['checked'] = true;
				} else {
					item['checked'] = false;
				}
			}
			this.tplTotal = res['totalCount'] || 0;
			// 如果没有一个被选中，则默认选中第一个
			if (!this.checkedTplId && this.templateList.length > 0) {
				this.checkOnlyOneTpl(this.templateList[0]['id']);
			}
			this.zone.run(() => { });
		}, err => {
			this.isLoadingTemplates = false;
			this.templateList = [];
			this.tplTotal = 0;
			this.checkedTpl = undefined;
			this.checkedTplId = '';
			this.checkedTplName = '';
			this.zone.run(() => { });
		});
	}

	selectTpl(item) {
		this.theTplDetail = item;
	}

	gotoTplDetail(item, event) {
		this.selectTpl(item);
		//处理 输入参数、输出参数、注意事项
		this.processDetailToArray();
		this.isTemplateDetail = true;
		event.stopPropagation();
	}

	useTplInTplList(item, event) {
		this.selectTpl(item);
		this.createBytpl();
	}
	useTplInTplDetail() {
		this.isTemplateDetail = false;
		this.createBytpl();
	}

	createBytpl() {
		this.checkOnlyOneTpl(this.theTplDetail.id);
		this.isTemplateList = !this.isTemplateList;

		this.checkedTplId = this.theTplDetail.id;
		this.checkedTplName = this.theTplDetail.displayName;
		this.checkedTpl = this.theTplDetail;
		this.runtime = this.checkedTpl.runtime.toLowerCase();
		this.runtimeChange({
			key: this.runtime
		});
	}

	checkOnlyOneTpl(id) {
		this.templateList.map(item => {
			if (item.id === id) {
				item['checked'] = true;
			} else {
				item['checked'] = false;
			}
		});
		if (this.templateList.filter(item => item['checked'] === true).length <= 0) {
			if (this.templateList[0]) {
				this.templateList[0]['checked'] = true;
			}
		}
	}

	useOtherTpl() {
		this.checkedTplId = '';
		this.checkedTplName = '';
		this.isTemplateList = true;
	}

	processDetailToArray() {
		let detailData = this.theTplDetail.detail;
		let inputData = detailData['input'];
		let outputData = detailData['output'];
		let warningData = detailData['warning'];
		if (inputData.length >= 0) {
			detailData['inputArr'] = inputData.split(';');
		} else {
			detailData['inputArr'] = [];
		}
		if (outputData.length >= 0) {
			detailData['outputArr'] = outputData.split(';');
		} else {
			detailData['outputArr'] = [];
		}
		if (warningData.length >= 0) {
			detailData['warningArr'] = warningData.split(';');
		} else {
			detailData['warningArr'] = [];
		}
	}

	tplDetailBack() {
		this.isTemplateDetail = false;
		this.isTemplateList = true;
	}

	getVPCList() {
		this.isLoadingVPC = true;
		this.fcsService.getVPCList(this.currentRegion.regionCode).subscribe(res => {
			this.isLoadingVPC = false;
			this.vpcList = [];
			if (res && res.vpcs) {
				this.vpcList = res.vpcs;
				this.vpcId = this.vpcList.length > 0 ? this.vpcList[0].vpc_id : undefined;
				// 设置subnet
				this.subnetList = this.vpcList.length > 0 ? this.vpcList[0].subnets : [];
				this.subnetId = this.subnetList.length > 0 ? this.subnetList[0].subnet_id : undefined;
			}
		}, err => {
			this.isLoadingVPC = false;
		})
	}

	getTemplateScenesConditions() {
		this.fcsService.getTemplateScenes().subscribe(res => {
			this.sceneClassifyList = res['scenes'] || [];
			this.sceneClassifyList.unshift({ name: '', displayName: '全部' });
		}, err => {
			this.sceneClassifyList = [];
			this.sceneClassifyList.unshift({ name: '', displayName: '全部' });
		});
	}

	virtualAccessChange(event) {
		if (!this.isVirtualAccess) {
			this.notChange = true;
		}
	}
	// 层配置开关
	virtualLayersChange(event) {
		if (event) {
			this.functionForm.addControl(
				'layersList', this.fb.array([
					this.fb.group({
						layer: [null, [Validators.required]],
						layerVersion: [null, [Validators.required]]
					})
				])
			)
		} else {
			this.functionForm.removeControl('layersList')
		}
	}

	vpcChange(event) {
		if (!this.notChange) {
			this.subnetList = [];
			this.subnetId = undefined;
			let subnets = this.vpcList.filter(item => item.vpc_id === this.vpcId);
			if (subnets.length > 0) {
				this.subnetList = subnets[0]['subnets'];
				this.subnetId = (this.subnetList.length > 0 ? this.subnetList[0].subnet_id : undefined);
			}
		}
		this.notChange = false;
		if (!this.vpcId) {
			this.vpcError = true;
		} else {
			this.vpcError = false;
		}
	}

	subnetChange(event) {
		if (!this.subnetId) {
			this.subnetError = true;
		} else {
			this.subnetError = false;
		}
	}

	createVPC() {
		let vpcUrl = Environment.application.productUrl + '/vpc/#/vpc?region=' + this.regionCode;
		window.open(vpcUrl, '_blank');
	}

	getEnvVariables(event) {
		this.envVariables = event['envVariableList'] || [];
		this.envValid = event['valid'];
	}

	getRegion() {
		let regionList = JSON.parse(sessionStorage.getItem('region-FCS'));
		regionList = regionList.map(item => {
			return {
				regionCode: item["regionId"],
				regionName: item["regionName"]
			}
		});
		if (regionList.length == 0) {
			this.msgService.error("Region 列表获取失败");
			return
		}
		let currentRegionCode = this.activatedRoute.snapshot.queryParams['regionCode'];
		let currentRegionName = this.activatedRoute.snapshot.queryParams['regionName'];
		if (currentRegionCode == "" || currentRegionName == "") {
			currentRegionCode = regionList[0]["regionCode"];
			currentRegionName = regionList[0]["regionName"];
		}
		this.currentRegion = {
			regionCode: currentRegionCode,
			regionName: currentRegionName,
		};
		this.regionList = regionList;
		this.regionCode = currentRegionCode;
		this.setControlVal('regionCode', currentRegionCode);
	}

	getApplicationList() {
		this.fcsService.getGroupList().subscribe(res => {
			this.isLoadingApplication = false;
			this.originApplicationList = JSON.parse(JSON.stringify(res));
			let a;
			this.applicationList = (res.length === 0 ? a : res);
			if (this.applicationId) {
				this.selectApplicationId = this.applicationId;
			} else if (this.groupId) {
				this.selectApplicationId = this.groupId;
			} else {
				this.applicationList != undefined && this.applicationList.length > 0 && this.setControlVal('groupId', this.applicationList[0].id);
			}
		}, error => {
			this.errorMsg = error;
			this.isLoadingApplication = false;
		})
	}

	runtimeChange(runtime) {
		this.runtime = runtime.key;
		this.getLayersList(); // 动态请求层列表
		this.functionForm.get('bindingLayers').setValue(false); // 切换运行环境重置层配置
		this.setControlVal("runtime", this.runtime);
		if (this.runtime != this.RuntimeCustomContainer) {
			this.setUploadShow();
      this.getCode(this.runtime);
    //   if (this.runtime.indexOf('golang') >= 0 || this.runtime.indexOf('java8') >= 0) {
    //     this.getCode(this.runtime);
    //   }
		}
		this.zone.run(() => { });
	}

	setShadow(value) {
		if (this.runtime === value) {
			const styles = {
				'box-shadow': 'rgba(81, 112, 255, 0.4) 0px 0px 10px 0px',
				'border': '1px solid #40a9ff'
			};
			return styles;
		}
	}

	setUploadShow() {
		if (this.runtime === 'golang1' || this.runtime === 'java8') {
			if (this.uploadTypeList.filter(item => item.value === 'online').length > 0) {
				let index = this.commonService.searchIndex(this.uploadTypeList, 'value', 'online')
				this.uploadTypeList.splice(index, 1);
			}
			this.uploadType = 'upload';
			if (this.runtime === 'golang1') {
				this.handlerPlaceHolder = 'main';
				this.setControlVal('handler', 'main');
			} else if (this.runtime === 'java8') {
				this.handlerPlaceHolder = 'example.HelloFC::handleRequest';
				this.setControlVal('handler', 'example.HelloFC::handleRequest');
			}
			this.setControlVal('fileName', '');
		} else {
			if (this.uploadTypeList.filter(item => item.value === 'online').length <= 0) {
				this.uploadTypeList.unshift({ label: '在线编辑', value: 'online' });
			}
			this.uploadType = 'online';
			this.handlerPlaceHolder = 'main';
			this.setControlVal('handler', 'index.handler');
			this.setControlVal('fileName', '');
		}
	}

	uploadTypeChange(event) {
		if (this.uploadType === 'online') {
			this.getCode(this.runtime);
		} else if (this.uploadType === 'upload' && this.localCode) {
		} else if (this.uploadType === 'oss') {
			//获取ossBucket
			this.getOssBuckets();
		}
	}

	fileSizeValidator() {
		if (this.uploadFiles.length > 0) { //计算上传文件的大小，每个文件Bite
			let file_size = this.uploadFiles[0].size / 1024 / 1024;
			if (file_size > this.fileMaxSize) {
				this.exceedFileMaxSize = true;
			} else {
				this.exceedFileMaxSize = false;
			}
		}
	}

  getOssBuckets() {
    this.isLoadingBucket = true;
    this.fcsService.getOssBucketList(1, 10000).subscribe(res => {
      if (res && res['data']) {
        let resBuckets = res.data;
        if (this.ossBucketList.length <= 0) {
          resBuckets.forEach(item => {
            this.ossBucketList.push({ label: item.bucketName, value: item.bucketName });
          })
        }
      }
      this.isLoadingBucket = false;
    }, err => {
      this.isLoadingBucket = false;
      // this.msgService.error('网络错误');
    })
  }

  getCode(runtime) {
    this.isCodeLoading = true;
    let name = 'default';
    if (this.createType === 'function') {
      name = 'default';
    } else if (this.createType === 'template') {
      name = this.checkedTpl.name;
    }
    this.fcsService.getDefaultCode(name, runtime).subscribe(res => {
      this.downLink = res['downloadLink'];
      if (this.runtime.indexOf('golang') >= 0 || this.runtime.indexOf('java8') >= 0) {
        this.codeService.getCodeZip(this.downLink).subscribe(res => {
          this.localCode = res || null;
          this.setUploadControl();
          this.validateFile(res);
          this.isCodeLoading = false;
          this.zone.run(() => { });
        }, err => {
          this.isCodeLoading = false;
          this.localCode = null;
        });
      } else {
        // python nodejs
        this.checkIdeReady(this.downLink);
        this.isCodeLoading = false;
      }
    }, err => {
      this.isCodeLoading = false;
      this.localCode = null;
    })
  }

	// 检查 vscode 加载成功
	// 并且 playground 插件也加载成功
	checkIdeReady(codeLink) {
		setTimeout(() => {
			if (this.codeEditor.nativeElement.contentWindow.executeCommand) {
				this.codeEditor.nativeElement.contentWindow.executeCommand("webPlayground.reloadZip", ""
				).then(() => this.loadIdeCode(codeLink)
				).catch(() => this.checkIdeReady(codeLink));
			} else {
				this.checkIdeReady(codeLink);
			}
		}, 200);
	}

	loadIdeCode(codeLink) {
		this.codeEditor.nativeElement.contentWindow.executeCommand("openEditors.closeAll");
		this.codeEditor.nativeElement.contentWindow.executeCommand("webPlayground.reloadZip", codeLink
		).then(
			success => {
				this.isCodeLoading = false;
				this.zone.run(() => { });
				if (!success) {
					this.msgService.error("代码加载失败");
				}
			}
		).catch(err => {
			this.isCodeLoading = false;
			this.zone.run(() => { });
			this.msgService.error("代码加载失败");
		});
	}

	setUploadControl() {
		if (this.runtime === 'golang1') {
			this.setControlVal('fileName', 'default-golang1.zip');
		} else if (this.runtime === 'java8') {
			this.setControlVal('fileName', 'code.zip');
		}
	}

	validateFile(arrayBuffer) {
		this.isZipFile = true;
		if (arrayBuffer && arrayBuffer['byteLength']) {
			if (arrayBuffer['byteLength'] / 1024 / 1024 > this.fileMaxSize) {
				this.exceedFileMaxSize = true;
			} else {
				this.exceedFileMaxSize = false;
			}
		}
	}

	/**
	 * 为表单控件赋值
	 * @param {string} formControlName 控件名称
	 * @param {(string | boolean)} val 设置的值
	 * @memberof APICreateRestComponent
	 */
	setControlVal(formControlName: string, val: string | boolean) {
		this.functionForm.get(formControlName).patchValue(val);
	}

	fileNameValidator(control: FormControl): any {
		let name: string = control.value;
		let pattern = new RegExp('^[^\\\\\/\:\*\?\"\<\>\|]+[\s]*[^\\\\\/\:\*\?\"\<\>\|]*\.zip$');
		if (!pattern.test(name)) {
			return { fileName: true };
		}
		return null;
	}

	fileNameValidator2(fileName) {
		let name: string = fileName;
		let pattern = new RegExp('^[^\\\\\/\:\*\?\"\<\>\|]+[\s]*[^\\\\\/\:\*\?\"\<\>\|]*\.zip$');
		if (pattern.test(name)) {
			this.isZipFile = true;
		} else {
			this.isZipFile = false;
		}
		let pattern2 = new RegExp('^[^\\\\\/\:\*\?\"\<\>\|]+[\s]*[^\\\\\/\:\*\?\"\<\>\|]*\.jar$');
		if (pattern2.test(name)) {
			this.isJarFile = true;
		} else {
			this.isJarFile = false;
		}
	}

	/**
	 * 名称校验
	 * @param {FormControl} control 控件实例
	 */
	nameValidator() {
		return (control: FormControl): { [s: string]: boolean } => {
			let name: string = control.value;
			let pattern = new RegExp('^[a-z][-a-z0-9]{0,18}[a-z0-9]$');
			if (!pattern.test(name)) {
				return { functionName: true };
			}
			return null;
		}
	}

	nameDuplicateValidator() {
		return (control: FormControl): any => {
			return control.valueChanges.pipe(
				distinctUntilChanged(),
				debounceTime(400),
				switchMap(() => this.isUserNameExist(control.value)),
				map(res => res['exist'] === true ? { duplicated: true } : null),
				first()
			);
		};
	}

	isUserNameExist(name: string): Observable<any> {
		if (!this.notFind) {
			if (this && this.selectApplicationId) {
				return this.fcsService.determineFunctionDuplicate(this.selectApplicationId, name);
			}
		}
		return new Observable((observer: Subscriber<any>) => {
			setTimeout(() => {
				observer.next({ exist: false });
			}, 2000);
		});
	}

	descriptionValid(control: FormControl): any {
		let des: string = control.value || '';
		// 最大支持500个英文字母、数字、空格、逗号、句号、中文
		let pattern = new RegExp('^[a-zA-Z0-9 ,，。.\u4e00-\u9fa5]{0,500}$');
		if (!des) return null;
		if (!pattern.test(des)) {
			return { description: true };
		}
		return null;
	}

	ossFileValidator(control: FormControl): any {
		let oss_file: string = control.value;
		let pattern = new RegExp('^/{1}(?:([^\\\\\/\:\*\?\"\<\>\|]+[\s]*[^\\\\\/\:\*\?\"\<\>\|]*/))*[^\\\\\/\:\*\?\"\<\>\|]+[\s]*[^\\\\\/\:\*\?\"\<\>\|]*\.zip$');
		if (!pattern.test(oss_file)) {
			return { ossFile: true };
		}
		return null;
	}

	formatterMemorySize = value => Math.floor(value / 128) * 128;

	getInvalidMessage(name) {
		let validResult = this.functionFormComponent ? this.functionFormComponent.getInvalidMessage(name) : null;
		return validResult;
	}

	focusFileName() {
		this.focusFileInput = true;
	}

	blurFileName() {
		this.focusFileInput = false;
	}

	onChange(e) {
		var obj = e.srcElement ? e.srcElement : e.target;
		if (obj.files.length == 0) {
			return false;
		}
		const file = obj.files[0]; // 获取从上传本地文件转换的数据
		this.setControlVal('fileName', file.name);
		this.fileNameValidator2(file.name);
		if (this.runtime.indexOf('java8') < 0) {
			if (!this.isZipFile) {
				return;
			}
		} else if (this.runtime.indexOf('java8') > 0) {
			if (!this.isZipFile && !this.isJarFile) {
				return;
			}
		}
		this.uploadFiles = obj.files;
		this.fileSizeValidator();
		if (this.exceedFileMaxSize) {
			return;
		}
		var size = file.size / 1024 / 1024;
		if (size > this.fileMaxSize) {
			this.msgService.error(`附件大小不能大于${this.fileMaxSize} +M！`);
			obj.value = "";
			return false;
		}
		const reader = new FileReader();
		reader.readAsDataURL(file);
		reader.onload = (e) => {
			this.localCode = e.target['result']; // 获取文件装换后的Base64位文件
			this.localCode = this.localCode.split('base64,')[1];
		};
	}

	ossFileChange(event) {
		this.ossFile = event;
	}

	triggerControlValidate(controlName) {
		let group = this.functionForm as FormGroup;
		group.controls[controlName].markAsDirty();
		group.controls[controlName].updateValueAndValidity();
	}

	/**
	 * 获取LATEST版本的 VersionId 和 VersionName ，即创建触发器参数中的 targetId 和 targetName
	 */
	getLATESTVersion(applicationId, functionId): Promise<any> {
		return new Promise((resolve, reject) => {
			this.fcsService.getVersionList(applicationId, functionId).subscribe(res => {
				this.LATESTobj = (res.data || []).filter(item => item.VersionName === 'LATEST')[0] || {};
				resolve(true)
			}, err => {
				this.LATESTobj = {};
				resolve(false);
			})
		})
	}

	validFileName(finallyValid) {
		let fileName = this.functionForm.get('fileName').value;
		this.fileNameValidator2(fileName);
		if (!this.isZipFile && !this.isJarFile) {
			finallyValid = false;
		}
		//校验大小
		this.fileSizeValidator();
		if (this.exceedFileMaxSize) {
			finallyValid = false;
		}
	}

	// 提交表单，创建函数
	async submit() {
		let id = this.msgService.loading('创建函数中...', { nzDuration: 0 }).messageId;
		let finallyValid = true;




		//环境变量校验
		this.envVariablesData = this.envVariables;
		if (!this.envValid) {
			this.needValid = true;
			finallyValid = false
		}
		let skip1 = '', skip2 = '', skip3 = '', skip4 = '', skip5 = '', skip6 = '';
		if (this.disableSubmit) {
			finallyValid = false;
		}
		switch (this.uploadType) {
			case 'online':
				skip1 = 'fileName';
				skip2 = 'ossBucket';
				skip3 = 'ossFile';
				break;
			case 'upload':
				skip1 = 'onlineCode';
				skip2 = 'ossBucket';
				skip3 = 'ossFile';
				break;
			default:
				skip1 = 'onlineCode';
				skip2 = 'fileName';
				break;
		}
		if (!this.isVirtualAccess) {
			skip4 = 'vpc';
			skip5 = 'subnet';
		} else {
			skip4 = '';
			skip5 = '';
		}
		skip6 = 'fileName';
		let group = this.functionForm as FormGroup;
		for (let i in group.controls) {
			if (i) {
				if (i == skip1 || i == skip2 || i == skip3 || i == skip4 || i == skip5 || i == skip6) {
					group.controls[i].clearValidators();
					group.controls[i].updateValueAndValidity();
				} else {
					group.controls[i].markAsDirty();
					group.controls[i].updateValueAndValidity();
				}
			}
		}

    // 校验本地上传的输入
    if(this.uploadType === 'upload'){
      if(!(this.functionForm.get('fileName').value) ){
        this.isZipFile = false;
        this.msgService.remove(id);
        return false;
      } else {
        this.isZipFile = true;
      }
    }
		if (this.exceedFileMaxSize) {
			finallyValid = false;
		}
		if (this.isCodeLoading) {
			finallyValid = false;
		}

		if (this.functionForm.get('runtime').value != this.RuntimeCustomContainer) {
			if (this.uploadType === 'online') {
				this.code = await this.codeEditor.nativeElement.contentWindow.executeCommand("webPlayground.generateZip");
			} else if (this.uploadType === 'upload') {
				if (this.localCode instanceof ArrayBuffer) {
					this.code = this.commonService.transformArrayBufferToBase64(this.localCode);
				} else {
					this.code = this.localCode;
				}
			}
		}

		if (this.createType === 'template' && this.checkedTplId && this.checkedTpl.triggerMetadataList.length > 0) {
			let triggerCreateValid = this.triggerCreate.validate();
			if (!triggerCreateValid) {
				finallyValid = false;
			}
		}
		//单独校验 fileName
		if (this.runtime.indexOf('java8') >= 0) {
			this.validFileName(finallyValid);
		}

		if (!finallyValid) {
			this.msgService.remove(id);
			return;
		}
		// 触发器数据
		if (this.createType === 'template' && this.checkedTpl.triggerMetadataList.length > 0) {
			this.triggerData = this.triggerCreate.submitData();
		}
		let param: { [index: string]: any } = {};
		// 设置参数

		// 增加层数据
		if (this.layersList) {
			let formControl = this.layersList.controls;
			for (let m = 0; m < formControl.length; m++) {
				let formGroup = formControl[m] as FormGroup;
				this.layerVersionIds.push(formGroup.get('layerVersion').value)
			}
		}

		let groupId = this.functionForm.get('groupId').value;
		param['functionName'] = this.functionForm.get('functionName').value;
		param['regionCode'] = this.functionForm.get('regionCode').value;
		this.regionName = this.regionList.filter(item => item.regionCode === param['regionCode'])[0]['regionName'];
		param['memorySize'] = this.functionForm.get('memorySize').value;
		param['timeout'] = this.functionForm.get('timeout').value;
		param['runtime'] = this.functionForm.get('runtime').value;
		param['handler'] = this.functionForm.get('handler').value;
		param['concurrency'] = this.functionForm.get('concurrency').value;
		param['reserveNumber'] = this.functionForm.get('reserveNumber').value;
		let description = this.functionForm.get('description').value;
		if (description != '') {
			param['description'] = description;
		}

		// custom-contaienr
		if (param['runtime'] == this.RuntimeCustomContainer) {
			param['containerImage'] = this.functionForm.get('containerImage').value;
			param['containerCommand'] = this.functionForm.get('containerCommand').value;
			param['containerArgs'] = this.functionForm.get('containerArgs').value;
			param['containerPort'] = this.functionForm.get('containerPort').value;
		}
		// initialize function
		if (this.functionForm.get('isInitialize').value) {
			param['initializeHandler'] = this.functionForm.get('initializeHandler').value;
			param['initializeTimeout'] = this.functionForm.get('initializeTimeout').value;
		}

		let internetAccess = this.functionForm.get('internetAccess').value;
		param['enablePublic'] = (internetAccess === false ? 0 : 1);
		if (this.isVirtualAccess) {
			param['enableVpc'] = 1;
			param['vpcInfo'] = {
				vpcId: this.vpcId,
				subnetId: this.subnetId
			}
		} else {
			param['enableVpc'] = 0;
		}
		param['environment'] = this.envVariables;
		let groupName;
		for (let item of this.applicationList) {
			if (item.id == groupId) {
				groupName = item.name;
				this.groupDisplayName = item.displayName;
				break;
			}
		}
		const interval = setInterval(() => {
			if (!group.pending) {
				clearInterval(interval);
				if (group.valid) {
					this.isReadonly = true;
					this.createFunctionMsgId = id;
					//选中的应用不存在(不存在是自己输入的)，先创建应用再创建函数
					if (this.notFind) {//没有找到应用
						this.disableSubmit = true;
						let groupParam = {
							"regionCode": this.currentRegion.regionCode,
							"regionName": this.currentRegion.regionName,
							"displayName": this.applicationList.filter(item => item.id === this.selectApplicationId)[0].displayName,
							"description": ''
						}
						this.fcsService.createGroup(groupParam).subscribe(data => {
							if (data && data.id && data.name) {
								if (this.uploadType === 'oss') {
									this.createFunctionPromise("oss", data.name, param['functionName'], data.id, param, id);
								} else {
									this.createFunctionPromise("", groupName, param['functionName'], groupId, param, id);
								}
							} else {
								this.isReadonly = false;
							}
						}, err => {
							this.isReadonly = false;
							this.disableSubmit = false;
							this.msgService.remove(id);
						});
					} else {
						this.disableSubmit = true;
						if (this.uploadType === 'oss') {
							this.createFunctionPromise("oss", groupName, param['functionName'], groupId, param, id);
						} else {
							this.createFunctionPromise("", groupName, param['functionName'], groupId, param, id);
						}
					}
				} else {
					this.msgService.remove(id);
					this.msgService.error("请检查表单参数")
				}
			}
		}, 500)
	}

	uploadCodeByOss(groupName, functionName, groupId, functionId): Promise<any> {
		return new Promise((resolve, reject) => {
			let bucket = this.functionForm.get('ossBucket').value,
				object = this.functionForm.get('ossFile').value;
			this.fcsService.updateOssCode(groupName, functionName, this.versionName, bucket, object, groupId, functionId).subscribe(res => {
				this.uploadParam = res;
				resolve(true);
			}, error => {
				resolve(false);
			});
		});
	}
	uploadCodeByFile(groupName, functionName, groupId, functionId): Promise<any> {
		return new Promise((resolve, reject) => {
			this.fcsService.updateCode(groupName, functionName, this.versionName, this.code, groupId, functionId).subscribe(res => {
				this.uploadParam = res;
				resolve(true);
			}, error => {
				resolve(false);
			});
		});
	}

	async createFunctionPromise(codeType, groupName, functionName, groupId, param, id) {
		// 先创建函数
		let createResult = await this.docreateFunction(groupId, param, id);
		if (createResult.createSuccess != undefined && !createResult.createSuccess) {
			this.msgService.error(createResult.data['message']);
		} else if (createResult.createSuccess != undefined && createResult.createSuccess) {
			// 再上传函数代码
			let uploadCodeResult
			if (param['runtime'] == this.RuntimeCustomContainer) {
				uploadCodeResult = true;
			} else if (codeType === "oss") {
				uploadCodeResult = await this.uploadCodeByOss(groupName, functionName, groupId, createResult.data.functionId);
			} else {
				uploadCodeResult = await this.uploadCodeByFile(groupName, functionName, groupId, createResult.data.functionId);
			}
			if (!uploadCodeResult) {
				// 上传函数代码失败
			} else {

				this.functionId = createResult.data.functionId;
				await this.getLATESTVersion(this.selectApplicationId, createResult.data.functionId);
				// 创建 custom-container 默认的 HTTP 触发器
				if (param['runtime'] == this.RuntimeCustomContainer) {
					await this.createDefaultHttpTrigger(createResult.data)
				}
				// 如果是使用模板创建的函数，检查是否有需要创建的触发器，有则创建，等待创建完后
				let createTriggerResult = await this.createTriggers();
				const redirectUrl = '/fcs-manage/function/detail/' + groupId + '/' + this.functionId + '/LATEST';
				// groupDisplayName
				this.router.navigate([redirectUrl],
					{
						queryParams: {
							groupId: groupId,
							functionId: this.functionId,
							groupDisplayName: this.groupDisplayName,
							regionName: this.regionName,
							regionCode: this.regionCode,
							functionName: createResult.data.functionName,
							groupName: createResult.data.groupName
						}
					});
			}
		}
		this.msgService.remove(id);
		this.msgService.success(createResult.data['message'] || '函数创建成功');

		this.isReadonly = false;
		this.disableSubmit = false;
	}

	docreateFunction(groupId, param, id): Promise<any> {
		param['regionCode'] = this.currentRegion.regionCode;
		param['regionName'] = this.currentRegion.regionName;
		param['bindingLayers'] = this.layerVersionIds; // 新增层
		return new Promise((resolve, reject) => {
			this.fcsService.createFuction(groupId, param).subscribe(
				data => { //functionId
					let functionId = data.functionId;
					this.createFunction = data;
					let createSuccess = true;
					if (!(data && data.functionName && data.functionId)) {
						createSuccess = false;
					}
					resolve({ createSuccess, data });
				},
				err => {
					resolve({ createError: true, err });
				});
		});
	}

	createTriggers(): Promise<any> {
		if (this.createType === 'template' && this.checkedTpl && this.checkedTpl.triggerMetadataList.length > 0) { //使用的模板有需要创建的触发器
			this.triggerMsgId = this.msgService.loading('创建触发器中......', { nzDuration: 0 }).messageId;
			this.isFinishCreatingTriggers = false;
			let params: { [index: string]: any } = {};
			params['groupId'] = this.selectApplicationId;
			params['groupName'] = this.applicationList.filter(item => item.id === this.selectApplicationId)[0]['name'] || '';
			params['groupDisplayName'] = this.applicationList.filter(item => item.id === this.selectApplicationId)[0]['displayName'] || '';
			params['funcId'] = this.createFunction['functionId'];
			params['funcName'] = this.createFunction['functionName'];
			params['regionCode'] = this.currentRegion.regionCode;
			params['regionName'] = this.currentRegion.regionName;
			return new Promise((resolve, reject) => {
				for (let i = 0; i < this.triggerData.length; i++) {
					let itemTrigger = this.triggerData[i];
					params['name'] = itemTrigger['name'];
					params['type'] = itemTrigger['type'];
					if (itemTrigger['type'] === 'timer') {
						params['triggerRule'] = itemTrigger['triggerRule'];
						if (itemTrigger.openInvokeEvent) {
							params['param'] = itemTrigger['invokeEvent'];
						}
					}
					if (itemTrigger['type'] === 'apig' || itemTrigger['type'] === 'oss') {
						params['isEnable'] = 1;
					} else {
						let isEnableValue = itemTrigger['isEnable'] ? 1 : 0;
						params['isEnable'] = isEnableValue;
					}
					params['targetType'] = 1;
					params['targetId'] = this.LATESTobj['VersionId'] || '';
					params['targetName'] = "LATEST";
					params['config'] = itemTrigger['config'];
					this.fcsService.createTrigger(params['groupId'], params['funcId'], params).subscribe(res => {
						if (i === this.triggerData.length - 1) {
							this.msgService.remove(this.triggerMsgId);
							this.isFinishCreatingTriggers = true;
							resolve({ isFinishCreatingTriggers: this.isFinishCreatingTriggers })
						}
					}, err => {
						if (i === this.triggerData.length - 1) {
							this.msgService.remove(this.triggerMsgId);
							this.isFinishCreatingTriggers = true;
							this.msgService.error('触发器创建失败');
							resolve({ isFinishCreatingTriggers: this.isFinishCreatingTriggers })
						}
					})
				}
			})
		} else {
			return Promise.resolve({ noCreateTrigger: true });
		}
	}

	createDefaultHttpTrigger(data): Promise<any> {
		let params: { [index: string]: any } = {};
		params['groupId'] = data.groupId;
		params['funcId'] = data.functionId;
		params['groupDisplayName'] = this.applicationList.filter(item => item.id === this.selectApplicationId)[0]['displayName'] || '';
		params['funcName'] = data.functionName;
		params['groupName'] = data.groupName;
		params['regionCode'] = data.regionCode;
		params['regionName'] = data.regionName;
		params['name'] = "default-http-trigger";
		params['type'] = "http";
		let config = {
			authType: "anonymous"
		}
		params['config'] = JSON.stringify(config);
		params['isEnable'] = 1;
		params['targetType'] = 1;
		params['targetId'] = this.LATESTobj['VersionId'] || '';
		params['targetName'] = "LATEST";
		return new Promise((resolve, reject) => {
			this.fcsService.createTrigger(params['groupId'], params['funcId'], params).subscribe(res => {
				resolve(true);
			});
		})
	}

	cancel() {
		this.router.navigate(['/fcs-manage/function']);
	}

	searchValueChange(event) {
		this.searchApplicationValue = event.trim();
		if (event.trim()) {
			if (this.originApplicationList == undefined || this.originApplicationList.length <= 0) {
				this.notFind = true;
			} else if (this.originApplicationList && this.originApplicationList.length > 0) {
				this.notFind = this.originApplicationList.filter(item => item.name === event.trim()).length > 0 ? false : true;
			}
			this.triggerFunctionNameValidate();
		}
	}

	triggerFunctionNameValidate() {
		let group = this.functionForm as FormGroup;
		group.controls['functionName'].markAsDirty();
		group.controls['functionName'].updateValueAndValidity();
	}

	expandApplicationChange(event) {
		if (event == false) { //关闭应用下拉框时
			this.triggerFunctionNameValidate();
			let willAdd = false;
			if (this.searchApplicationValue != '') { //添加在application头部
				if (this.applicationList == undefined || this.applicationList.length <= 0) {
					this.applicationList = [];
					willAdd = true;
				} else {
					if (this.applicationList.filter(item => item.name === this.searchApplicationValue).length <= 0) {
						willAdd = true;
					}
				}
				if (willAdd) {
					this.applicationList.unshift({
						displayName: this.searchApplicationValue,
						id: (new Date().getTime() + '')
					})
				}
			}
			if (willAdd) {
				if (this.applicationList != undefined && this.applicationList.length > 0) {
					this.selectApplicationId = this.applicationList[0].id;
				}
				this.notFind = true;
			}
		} else {
			this.applicationList = JSON.parse(JSON.stringify(this.originApplicationList));
		}
		if (this.originApplicationList && this.originApplicationList.length > 0) {
			this.notFind = this.originApplicationList.filter(item => item.id === this.selectApplicationId.trim()).length > 0 ? false : true;
		}
	}

	applicationIdChange(event) {
		if (event != undefined && event.trim() != '') {
			if (!this.originApplicationList || this.originApplicationList.length < 0) {
				this.notFind = true;
			} else {
				this.notFind = this.originApplicationList.filter(item => item.id === event.trim()).length > 0 ? false : true;
			}
		}
	}

	getCirTagList() {
		this.fcsService.getCirTagList().subscribe(res => {
			let data = JSON.parse(JSON.stringify(res));
			data = data.map(item => {
				let imageAndTag = item.path + ":" + item.name;
				let idx = imageAndTag.indexOf("/");
				imageAndTag = imageAndTag.slice(idx + 1);
				item.image = imageAndTag;
				return item;
			});
			this.cirImageList = data;
		}, err => {
		});
	}

	ngOnDestroy() {
		this.msgService.remove(this.createFunctionMsgId);
		this.msgService.remove(this.triggerMsgId);
	}

}
